package main

import (
	"github.com/Logicalis/asn1"
	"gopkg.in/asn1-ber.v1"
)

type SvASDU struct {
	SvID     string  `asn1:"tag:0"`
	DataSet  string  `asn1:"optional,tag:1"`
	SmpCnt   [2]byte `asn1:"tag:2"`
	ConfRev  [4]byte `asn1:"tag:3"`
	RefrTm   [8]byte `asn1:"optional,tag:4"`
	SmpSynch [1]byte `asn1:"tag:5"`
	SmpRate  [2]byte `asn1:"optional,tag:6"`
	SmpData  []byte  `asn1:"tag:7"`
	SmpMod   [2]byte `asn1:"optional,tag:8"`
}

type SvApp struct {
	NoASDU         int      `asn1:"tag:0"`
	SequenceOfASDU []SvASDU `asn1:"tag:2"`
}

func EncodeSv(svApp *SvApp) ([]byte, error) {
	ctx := asn1.NewContext()
	// Use BER for encoding and decoding.
	ctx.SetDer(false, false)

	apdu, err := ctx.EncodeWithOptions(*svApp, "application,tag:0")
	return apdu, err
}

func DecodeSv(apdu []byte) (*SvApp, error) {
	ctx := asn1.NewContext()
	// Use BER for encoding and decoding.
	ctx.SetDer(false, false)

	svdec := SvApp{}

	_, err := ctx.DecodeWithOptions(apdu, &svdec, "application,tag:0")

	return &svdec, err
}

func DecodeSvFast(apdu []byte) (*SvApp, error) {
	p, err := ber.DecodePacketErr(apdu)
	if err != nil {
		return nil, err
	}
	sv := SvApp{}
	for _, ch1 := range p.Children {
		if (ch1.Identifier == ber.Identifier{128, 0, 0}) { // NoASDU default N=1
			sv.NoASDU = int(DecodeUint(ch1.Data.Bytes()))
			sv.SequenceOfASDU = make([]SvASDU, sv.NoASDU)
		} //else if (ch1.Identifier == ber.Identifier{128, 32, 2}) { // SequenceOfASDU
		//ch1.Description = "SequenceOfASDU"
		//}
		for idx, ch2 := range ch1.Children {
			//if (ch2.Identifier == ber.Identifier{0, 32, 16}) {	// ASDU 0...N-1 default N=1
			//	ch2.Description = "ASDU"
			//}
			for _, ch3 := range ch2.Children {
				if (ch3.Identifier == ber.Identifier{128, 0, 0}) { // SvID
					//ch3.Description = "SvID"
					sv.SequenceOfASDU[idx].SvID = string(ch3.Data.Bytes())
				} else if (ch3.Identifier == ber.Identifier{128, 0, 1}) { // DataSet
					//ch3.Description = "DataSet"
					sv.SequenceOfASDU[idx].DataSet = string(ch3.Data.Bytes())
				} else if (ch3.Identifier == ber.Identifier{128, 0, 2}) { // SmpCnt
					//ch3.Description = "SmpCnt"
					copy(sv.SequenceOfASDU[idx].SmpCnt[0:], ch3.Data.Bytes())
				} else if (ch3.Identifier == ber.Identifier{128, 0, 3}) { // ConfRev
					//ch3.Description = "ConfRev"
					copy(sv.SequenceOfASDU[idx].ConfRev[0:], ch3.Data.Bytes())
				} else if (ch3.Identifier == ber.Identifier{128, 0, 4}) { // RefrTm
					//ch3.Description = "RefrTm"
					copy(sv.SequenceOfASDU[idx].RefrTm[0:], ch3.Data.Bytes())
				} else if (ch3.Identifier == ber.Identifier{128, 0, 5}) { // SmpSynch
					//ch3.Description = "SmpSynch"
					copy(sv.SequenceOfASDU[idx].SmpSynch[0:], ch3.Data.Bytes())
				} else if (ch3.Identifier == ber.Identifier{128, 0, 6}) { // SmpRate
					//ch3.Description = "SmpRate"
					copy(sv.SequenceOfASDU[idx].SmpRate[0:], ch3.Data.Bytes())
				} else if (ch3.Identifier == ber.Identifier{128, 0, 7}) { // SmpData
					//ch3.Description = "SmpData"
					sv.SequenceOfASDU[idx].SmpData = ch3.Data.Bytes()
				} else if (ch3.Identifier == ber.Identifier{128, 0, 8}) { // SmpMod
					//ch3.Description = "SmpMod"
					copy(sv.SequenceOfASDU[idx].SmpMod[0:], ch3.Data.Bytes())
				}
			}
		}
	}
	return &sv, nil
}
